package com.lianqi.emcpframework.dataaccess.internal;

import com.lianqi.emcpframework.dataaccess.DataAccess;
import com.lianqi.emcpframework.dataaccess.FieldFilterType;
import com.lianqi.emcpframework.dataaccess.OperationType;
import com.lianqi.emcpframework.dataaccess.SetScope;
import org.apache.shiro.authz.permission.WildcardPermission;
import org.apache.shiro.util.StringUtils;

import java.util.Set;
import java.util.stream.Collectors;

/**
 * @program emcp-framework
 * @ClassName SimpleDataAccess
 * @description: 通用数据权限定义
 * @author: sky
 * @create: 2019/05/30 15:06
 */

public class SimpleDataAccess extends WildcardPermission implements DataAccess {

    /**
     * 数据权限控制业务对象
     * 如：User   Role
     */
    String domain;
    /**
     * 对应的操作类型
     * @see OperationType
     */
    Set<String> actions;
    /**
     * 数据集合过滤 类型
     * @see SetScope
     */
    String setFilterType;
    /**
     * 字段过滤类型
     * @see FieldFilterType
     */
    String fieldFilterType;

    /**
     * 集合过滤条件 如：机构ID 集合
     */
    String setScope;
    /**
     * 字段过滤集合
     */
    String filterFields;
    /**
     * 权限定义
     *  domain:actions:setFilterType:fieldFilterType
     */
    String definition;


    public SimpleDataAccess() {
        this.domain = this.getClass().getName();
        setParts(this.getClass().getName());
    }


    public SimpleDataAccess(String domain, String actions, String setFilterType) {
        new SimpleDataAccess(domain,actions,setFilterType,null,null,null);
    }


    public SimpleDataAccess(String domain, String actions,
                            String setFilterType, String fieldFilterType) {
       new SimpleDataAccess(domain,actions,setFilterType,fieldFilterType,null,null);
    }

    public SimpleDataAccess(String domain, String actions,
                            String setFilterType, String fieldFilterType, String setScope, String filterFields) {
        this.domain = domain;
        this.actions = StringUtils.splitToSet(actions, SUBPART_DIVIDER_TOKEN);
        this.setFilterType = setFilterType;
        this.fieldFilterType = fieldFilterType;
        this.setScope = setScope;
        this.filterFields = filterFields;
        encodeParts(this.domain, actions, setFilterType, fieldFilterType);
    }

    @Override
    public String getDomain() {
        return domain;
    }

    public void setDomain(String domain) {
        this.domain = domain;
        setParts(domain, actions, setFilterType, fieldFilterType);
    }

    @Override
    public Set<String> getActions() {
        return actions;
    }

    public void setActions(Set<String> actions) {
        this.actions = actions;
        setParts(domain, actions, setFilterType, fieldFilterType);
    }

    @Override
    public String getSetFilterType() {
        return setFilterType;
    }

    public void setSetFilterType(String setFilterType) {
        this.setFilterType = setFilterType;
    }

    @Override
    public String getFieldFilterType() {
        return fieldFilterType;
    }

    public void setFieldFilterType(String fieldFilterType) {
        this.fieldFilterType = fieldFilterType;
    }

    public void setSetScope(String setScope) {
        this.setScope = setScope;
    }

    @Override
    public Set<String> getFilterFields() {
        return StringUtils.splitToSet(filterFields, SUBPART_DIVIDER_TOKEN);
    }

    public void setFilterFields(String filterField) {
        this.filterFields = filterField;
    }

    @Override
    public Set<String> getSetScope() {
        return StringUtils.splitToSet(this.setScope, SUBPART_DIVIDER_TOKEN);
    }

    public String getDefinition() {
        return definition;
    }

    public void setDefinition(String definition) {
        this.definition = definition;
        setParts(definition);
        if (getParts() != null && getParts().size() >= 1) {
            this.domain = getParts().get(0).stream().findFirst().get();
        }
        if (getParts() != null && getParts().size() >= 2) {
            this.actions = getParts().get(1).stream().collect(Collectors.toSet());
        }
        if (getParts() != null && getParts().size() >= 3) {
            this.setFilterType = getParts().get(2).stream().findFirst().get();
        }
        if (getParts() != null && getParts().size() >= 4 ) {
            this.fieldFilterType = getParts().get(3).stream().findFirst().get();
        }
    }

    protected void setParts(String domain, Set<String> actions, String setFilterType, String fieldFilterType) {
        String actionsString = StringUtils.toDelimitedString(actions, SUBPART_DIVIDER_TOKEN);
        encodeParts(domain, actionsString, setFilterType, fieldFilterType);
        this.domain = domain;
        this.actions = actions;
        this.setFilterType = setFilterType;
        this.fieldFilterType = fieldFilterType;
    }

    private void encodeParts(String domain, String actions, String setFilterType, String fieldFilterType) {
        if (!StringUtils.hasText(domain)) {
            throw new IllegalArgumentException("domain argument cannot be null or empty.");
        }
        StringBuilder sb = new StringBuilder(domain);

        if (!StringUtils.hasText(actions)) {
            if (StringUtils.hasText(setFilterType)) {
                sb.append(PART_DIVIDER_TOKEN).append(WILDCARD_TOKEN);
            }
        } else {
            sb.append(PART_DIVIDER_TOKEN).append(actions);
        }
        if (!StringUtils.hasText(setFilterType)) {
            if (!StringUtils.hasText(fieldFilterType)) {
                sb.append(PART_DIVIDER_TOKEN).append(FieldFilterType.none.getValue());
            }
        } else {
            sb.append(PART_DIVIDER_TOKEN).append(setFilterType);
        }
        if (StringUtils.hasText(fieldFilterType)) {
            sb.append(PART_DIVIDER_TOKEN).append(fieldFilterType);
        }
        this.definition = sb.toString();
        setParts(sb.toString());
    }

}
